// utils/coroutine.js - 异步操作控制工具

/**
 * 延时函数 - 返回一个Promise，在指定时间后resolve
 * @param {number} timeout 延时时间（毫秒）
 * @returns {Promise<void>} Promise对象
 */
export const delay = (timeout) => {
  return new Promise(resolve => setTimeout(resolve, timeout));
};

/**
 * 下一个微任务执行
 * @returns {Promise<void>} Promise对象
 */
export const nextTick = () => {
  return new Promise(resolve => {
    // 优先使用微任务API
    if (typeof queueMicrotask === 'function') {
      queueMicrotask(resolve);
    } else {
      // 降级处理
      setTimeout(resolve, 0);
    }
  });
};

/**
 * 串行化执行函数 - 确保多次调用同一函数时，前一次执行完毕后才执行下一次
 * @param {Function} fn 需要串行化的函数
 * @returns {Function} 串行化后的函数
 */
export const serialize = (fn) => {
  let pending = Promise.resolve();
  
  return function(...args) {
    const result = pending.then(() => fn.apply(this, args));
    pending = result.catch(() => {});
    return result;
  };
};

/**
 * 超时控制 - 给Promise添加超时限制
 * @param {Promise} promise 原始Promise
 * @param {number} ms 超时时间（毫秒）
 * @param {string} errorMessage 超时错误消息
 * @returns {Promise} 带超时控制的Promise
 */
export const timeout = (promise, ms, errorMessage = '操作超时') => {
  let timeoutId;
  
  const timeoutPromise = new Promise((_, reject) => {
    timeoutId = setTimeout(() => {
      reject(new Error(errorMessage));
    }, ms);
  });
  
  return Promise.race([
    promise,
    timeoutPromise
  ]).finally(() => {
    clearTimeout(timeoutId);
  });
};

/**
 * 重试函数 - 在失败时自动重试
 * @param {Function} fn 需要重试的函数
 * @param {Object} options 重试选项
 * @param {number} options.maxRetries 最大重试次数
 * @param {number} options.delay 重试间隔时间（毫秒）
 * @param {Function} options.shouldRetry 判断是否应该重试的函数
 * @returns {Promise} 重试结果
 */
export const retry = async (fn, options = {}) => {
  const { 
    maxRetries = 3, 
    delay: delayTime = 1000, 
    shouldRetry = () => true 
  } = options;
  
  let lastError;
  
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      if (attempt > 0) {
        await delay(delayTime);
      }
      
      return await fn();
    } catch (error) {
      lastError = error;
      
      if (attempt >= maxRetries || !shouldRetry(error)) {
        break;
      }
      
      console.warn(`重试操作: 第 ${attempt + 1} 次 (最大 ${maxRetries} 次)`);
    }
  }
  
  throw lastError;
};

/**
 * 批量执行Promise - 控制并发数
 * @param {Array} items 要处理的数据项数组
 * @param {Function} fn 处理函数，返回Promise
 * @param {number} concurrency 并发数
 * @returns {Promise<Array>} 结果数组
 */
export const batch = async (items, fn, concurrency = 5) => {
  const results = [];
  const running = new Set();
  
  async function startItem(item, index) {
    const promise = Promise.resolve().then(() => fn(item, index));
    running.add(promise);
    
    try {
      const result = await promise;
      results[index] = result;
      return result;
    } finally {
      running.delete(promise);
    }
  }
  
  let index = 0;
  while (index < items.length) {
    if (running.size < concurrency) {
      startItem(items[index], index);
      index++;
    } else {
      await Promise.race(running);
    }
  }
  
  await Promise.all(running);
  return results;
};

export default {
  delay,
  nextTick,
  serialize,
  timeout,
  retry,
  batch
};